package com.hypertian.demo.view.progress.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.text.Layout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Scroller;

/**
 * Created by hypertian on 2016/8/22.
 * Desc 组合调仓进度自定义SeekBar
 * <p>
 * void setValueChangeListener(OnValueChangeListener listener) 设置回调监听接口
 * <p>
 * void initValue(int currValue, int maxValue, int minValue); 初始化进度条
 * <p>
 * void setCurrValue(int currValue); 设置当前值
 * <p>
 * void setMaxValue(int maxValue);  设置最大值
 * <p>
 * void setMinValue(int maxValue);  设置最小值
 */
public class PikerSeekBarView extends View {
    //刻度盘精度
    private static final int MOD_TYPE = 10;
    //每隔点之间的间距
    private static final int ITEM_HEIGHT_DIVIDER = 10;
    //三个点R半径的大小
    private static final int ITEM_R_LEVEL_ONE = 4;
    private static final int ITEM_R_LEVEL_TWO = 10;
    private static final int ITEM_R_LEVEL_THREE = 16;
    //点下方Text的大小
    private static final int TEXT_SIZE = 15;
    //选中的三角形的大小
    private static final int TRIANGLE_WIDTH = 30;
    private static final int TRIANGLE_HEIGHT = 20;

    private static final String mBackGroundColor = "#1E252D";
    private static final String mTextColor = "#528EF6";
    private static final String mCircleColor = "#528EF6";
    //选中的颜色
    private static final String mSelectColor = "#528EF6";

    //屏幕密度
    private float mDensity;
    //初始化当前值，最大值，最小值
    private int mValue = 50;
    private int mMaxValue = 100;
    private int mMinValue = 0;
    //精度
    private int mModType = MOD_TYPE;
    //每个点之间间距
    private int mCircleDivider = ITEM_HEIGHT_DIVIDER;
    private int mLastX, mMove;
    //控件的宽度和高度
    private int mWidth, mHeight;

    private int mMinVelocity;
    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;

    private OnValueChangeListener mListener;

    private Paint mCirclePaint = new Paint();
    private Paint mSelectPaint = new Paint();

    public interface OnValueChangeListener {
        void onValueChange(int value);
    }

    public PikerSeekBarView(Context context) {
        this(context, null);
    }

    public PikerSeekBarView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public PikerSeekBarView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        setPadding(50, 0, 50, 0);
        setBackgroundColor(Color.parseColor(mBackGroundColor));
        mScroller = new Scroller(context);
        mDensity = context.getResources().getDisplayMetrics().density;
        //获得允许执行一个fling手势动作的最小速度值
        mMinVelocity = ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();
    }

    /**
     * 设置当前值
     *
     * @param currValue 当前进度
     */
    public void setCurrValue(int currValue) {
        initValue(currValue, mMaxValue, mMinValue);
    }

    /**
     * 设置最小值
     *
     * @param minValue 最小值
     */
    public void setMinValue(int minValue) {
        if (minValue > mValue)
            minValue = mValue;
        initValue(mValue, mMaxValue, minValue);
    }

    /**
     * 设置最大值
     *
     * @param maxValue 最大值
     */
    public void setMaxValue(int maxValue) {
        if (maxValue < mValue)
            maxValue = mValue;
        initValue(mValue, maxValue, mMinValue);
    }

    /**
     * @param currValue 初始值
     * @param maxValue  最大值
     */
    public void initValue(int currValue, int maxValue, int minValue) {
        mValue = currValue;
        mMaxValue = maxValue;
        mMinValue = minValue;

        invalidate();

        mLastX = 0;
        mMove = 0;
        notifyValueChange();
    }

    /**
     * 设置用于接收结果的监听器
     */
    public void setValueChangeListener(OnValueChangeListener listener) {
        mListener = listener;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        mWidth = getWidth();
        mHeight = getHeight();
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawScaleLine(canvas);
        drawMiddleLine(canvas);
    }


    /**
     * 从中间往两边开始画小圆点
     */
    private void drawScaleLine(Canvas canvas) {
        canvas.save();

        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setColor(Color.parseColor(mCircleColor));

        TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextSize(TEXT_SIZE * mDensity);
        textPaint.setColor(Color.parseColor(mTextColor));
        float textWidth = Layout.getDesiredWidth("0", textPaint);

        int width = mWidth;
        int drawCount = 0;
        float xPosition;
        float yPosition = getHeight() / 3;
        int alpha;

        for (int i = 0; drawCount <= 4 * width; i++) {
            //画右边圆点
            xPosition = (width / 2 - mMove) + i * mCircleDivider * mDensity;//计算圆的X坐标
            alpha = 150 - (int) (510 * (Math.abs(mWidth / 1.5 - xPosition)) / mWidth);
            if (xPosition + getPaddingRight() < mWidth && (mValue + i) <= mMaxValue) {
                if (xPosition == mWidth / 2) {
                    textPaint.setAlpha(255);
                } else {
                    textPaint.setAlpha(alpha);
                    mCirclePaint.setAlpha(alpha);
                }
                //检测是否到整数刻度，检测最小刻度与下一整数刻度之间的差值，若小于2则不显示最小值，反之则显示
                if ((mValue + i) % mModType == 0 || ((mValue + i) % mModType > 2 && (mValue + i) == mMaxValue)) {
                    canvas.drawCircle(xPosition, yPosition, ITEM_R_LEVEL_TWO, mCirclePaint);
                    canvas.drawText(String.valueOf((mValue + i)), countLeftStart((mValue + i), xPosition, textWidth), getHeight() - textWidth, textPaint);
                } else {
                    canvas.drawCircle(xPosition, yPosition, ITEM_R_LEVEL_ONE, mCirclePaint);
                }
            }

            //画左边圆点
            xPosition = (width / 2 - mMove) - i * mCircleDivider * mDensity;
            if (xPosition > getPaddingLeft() && (mValue - i) >= mMinValue) {
                //道理同上
                if ((mValue - i) % mModType == 0 || ((mValue - i) % mModType < 8 && (mValue - i) == mMinValue)) {
                    canvas.drawCircle(xPosition, yPosition, ITEM_R_LEVEL_TWO, mCirclePaint);
                    canvas.drawText(String.valueOf((mValue - i)), countLeftStart((mValue - i), xPosition, textWidth), getHeight() - textWidth, textPaint);
                } else {
                    canvas.drawCircle(xPosition, yPosition, ITEM_R_LEVEL_ONE, mCirclePaint);
                }
            }
            drawCount += 2 * mCircleDivider * mDensity;
        }

        canvas.restore();
    }

    /**
     * 计算数字显示位置的辅助方法
     */
    private int countLeftStart(int value, float xPosition, float textWidth) {
        float xp;
        if (value < 20) {
            xp = xPosition - (textWidth * 1 / 2);
        } else {
            xp = xPosition - (textWidth * 2 / 2);
        }
        return (int) xp;
    }

    /**
     * 画中间的指示圆
     */
    private void drawMiddleLine(Canvas canvas) {
        canvas.save();
        mSelectPaint.setColor(Color.parseColor(mSelectColor));
        Path mTrianglePath = new Path();
        mTrianglePath.moveTo(mWidth / 2 - TRIANGLE_WIDTH / 2, 0);
        mTrianglePath.lineTo(mWidth / 2, TRIANGLE_HEIGHT);
        mTrianglePath.lineTo(mWidth / 2 + TRIANGLE_WIDTH / 2, 0);
        mTrianglePath.close();
        canvas.drawPath(mTrianglePath, mSelectPaint);
        canvas.drawCircle(mWidth / 2, mHeight / 3, ITEM_R_LEVEL_THREE, mSelectPaint);
        canvas.restore();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int xPosition = (int) event.getX();

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();//获得VelocityTracker类实例
        }
        mVelocityTracker.addMovement(event);//将事件加入到VelocityTracker类实例中

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mScroller.forceFinished(true);

                mLastX = xPosition;
                mMove = 0;
                break;
            case MotionEvent.ACTION_MOVE:
                mMove += (mLastX - xPosition);
                changeMoveAndValue();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                countMoveEnd();
                countVelocityTracker();
                return false;
            default:
                break;
        }

        mLastX = xPosition;
        return true;
    }

    /**
     * VelocityTracker主要用跟踪触摸屏事件（flinging事件和其他gestures手势事件）的速率。
     * 用addMovement(MotionEvent)函数将Motion event加入到VelocityTracker类实例中。
     * 可以使用getXVelocity() 或getXVelocity()获得横向和竖向的速率到速率时，
     * 但是使用它们之前要先调用computeCurrentVelocity(int)来初始化速率的单位 。
     */
    private void countVelocityTracker() {
        //值为1000表示一秒（1000毫秒）时间单位内运动了多少个像素
        mVelocityTracker.computeCurrentVelocity(1000);
        float xVelocity = mVelocityTracker.getXVelocity();
        if (Math.abs(xVelocity) > mMinVelocity) {
            /**
             * startX 滚动起始点X坐标
             * startY 滚动起始点Y坐标
             * velocityX   当滑动屏幕时X方向初速度，以每秒像素数计算
             * velocityY   当滑动屏幕时Y方向初速度，以每秒像素数计算
             * minX    X方向的最小值，scroller不会滚过此点。
             * maxX    X方向的最大值，scroller不会滚过此点。
             * minY    Y方向的最小值，scroller不会滚过此点。
             * maxY    Y方向的最大值，scroller不会滚过此点。
             */
            mScroller.fling(0, 0, (int) xVelocity, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
        }
    }

    private void changeMoveAndValue() {
        int tValue = (int) (mMove / (mCircleDivider * mDensity));
        if (Math.abs(tValue) > 0) {
            mValue += tValue;
            mMove -= tValue * mCircleDivider * mDensity;
            if (mValue <= mMinValue || mValue > mMaxValue) {//如果到达两端，则强制
                mValue = mValue <= mMinValue ? mMinValue : mMaxValue;
                mMove = 0;
                mScroller.forceFinished(true);//强制终止滚动
            }

            notifyValueChange();
        }
        postInvalidate();
    }

    private void countMoveEnd() {
        int roundMove = Math.round(mMove / (mCircleDivider * mDensity));
        mValue = mValue + roundMove;
        mValue = mValue <= 0 ? 0 : mValue;
        mValue = mValue > mMaxValue ? mMaxValue : mValue;

        mLastX = 0;
        mMove = 0;

        notifyValueChange();
        postInvalidate();
    }

    private void notifyValueChange() {
        if (null != mListener) {
            if (mModType == MOD_TYPE) {
                mListener.onValueChange(mValue);
            }
        }
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {//返回值为false，表明滚动动作已经结束。
            //getFinalX()返回滚动结束位置。仅针对“fling”手势有效,最终位置X方向距离原点的绝对距离
            if (mScroller.getCurrX() == mScroller.getFinalX()) { // over
                countMoveEnd();
            } else {
                int xPosition = mScroller.getCurrX();//返回当前滚动X方向的偏移,距离原点X方向的绝对值
                mMove += (mLastX - xPosition);
                changeMoveAndValue();
                mLastX = xPosition;
            }
        }
    }
}
